﻿// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Copyright (c) 2011, Dr. Masroor Ehsan
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the author nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

using System;
using System.IO;
using System.Linq;
using System.Threading;
using Common.Logging;
using Quartz;

namespace dseScraper
{
    public class ScraperJob : IJob
    {
        private readonly ILog _log;
        private ScheduleChecker _checker;

        public ScraperJob()
        {
            _log = LogManager.GetLogger(GetType());
            _checker = new ScheduleChecker();
        }

        #region IJob Members

        public void Execute(IJobExecutionContext context)
        {
            var checker = new ScheduleChecker();
            if (checker.CheckTime(DateTime.Now))
            {
                var ctx = new WorkContext
                              {
                                  BatchNum = BatchNumGenerator.Instance.Next(),
                                  Log = _log,
                                  Url = @"http://dsebd.org/latest_share_price_all.php",
                                  Referer = @"http://dsebd.org/latest_share_price_scroll_l.php"
                              };
                ThreadPool.QueueUserWorkItem(DoWork, ctx);
            }
            else
            {
                BatchNumGenerator.Instance.Reset();
            }
        }

        #endregion

        private static void DoWork(object context)
        {
            var ctx = (WorkContext) context;
            var batch = ctx.BatchNum;
            ctx.Log.Info(batch + ": Getting html...");
            var dt = DateTime.Now;
            
            DateTime utcTime;
            var html = WebDownloader.DownloadHtml(new Uri(ctx.Url), ctx.Referer, true, out utcTime).Trim();
            
            var seconds = (DateTime.Now - dt).Seconds;

            if (string.IsNullOrEmpty(html))
            {
                ctx.Log.Error(batch + ": Empty HTML downloaded.");
                return;
            }

            var fname = BatchNumGenerator.RawFilename(batch);
            Extensions.EnsureDir(fname);
            using (var fs = new StreamWriter(fname))
            {
                fs.Write(html);
            }

            ctx.Log.Info(string.Format("{0}: {1} bytes downloaded in {2} second(s)", batch, html.Length, seconds));
            
            var sanitizer = new SanitizeHtml();
            html = sanitizer.Execute(html);

            ctx.Log.Info(string.Format("{0}: {1} bytes after sanitization", batch, html.Length));
            
            var parser = new SgmlQuotesParser();
            var quotes = parser.Execute(html, utcTime);

            ctx.Log.Info(string.Format("{0}: Got {1} quotes", batch, quotes.Count));

            var filteredQuotes = quotes.Where(quote => quote.Volume > 0).ToList();
            ctx.Log.Info(string.Format("{0}: Filtered to {1} quotes", batch, filteredQuotes.Count));

            if (filteredQuotes.Count > 0)
            {
                fname = BatchNumGenerator.QuotesFilename(batch);
                Extensions.EnsureDir(fname);
                using (var fs = new StreamWriter(fname))
                {
                    foreach (var quote in filteredQuotes)
                    {
                        fs.WriteLine(quote);
                    }
                }
            }

            ctx.Log.Info(string.Format("{0}: Done", batch));
        }

        #region Nested type: WorkContext

        private class WorkContext
        {
            public int BatchNum;
            public ILog Log;
            public string Referer;
            public string Url;
        }

        #endregion
    }
}